package com.zny;

import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.WKBReader;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBWriter;
import org.locationtech.jts.io.WKTReader;

import java.util.ArrayList;
import java.util.List;

public class GeoToolsUtil {
    private static GeometryFactory GEOMETRYFACTORY = JTSFactoryFinder.getGeometryFactory();
    private static WKTReader WKTREADER = new WKTReader(GEOMETRYFACTORY);
    private static WKBWriter WKBWRITER = new WKBWriter();
    private static WKBReader WKBREADER = new WKBReader();

    /**
     * 以下内容为几何地理实体类的wkt形式样例，供开发参考
     *
     * POINT -> POINT(108.36 34.36)
     *
     * LINESTRING -> LINRSTRING("108.36 34.36","108.37 34.37","108.37 34.37")
     *
     * POLYGON -> POLYGON((108.36 34.36,108.37 34.37,108.38 34.38,108.36 34.36))
     *
     * POLYGON -> POLYGON((108.36 34.36,108.37 34.37,108.38 34.38,108.36 34.36),(108.36 34.36,108.37 34.37,108.38 34.38,108.36 34.36))
     *
     * MULTIPOLYGON  -> MULTIPOLYGON((1 1,5 1,5 5,5 1,1 1 ),(2 2,6 3,6 4,6 5,2 2),( 2 1, 3 2,3 3, 2 1))
     *
     */

    /**
     * 面转换为线
     *
     * @param geom
     * @return
     */
    public static Geometry polygon2LineString(Geometry geom) {

        String geometryType = geom.getGeometryType().toUpperCase();
        Geometry res;

        if ("MULTIPOLYGON".equals(geometryType)) {
            int geoNum = geom.getNumGeometries();
            ArrayList<LineString> lineList = new ArrayList<>();
            if (geoNum > 1) {
                // 包含多个面，面中包含环
                for (int i = 0; i < geoNum; i++) {
                    Polygon geo = (Polygon) geom.getGeometryN(i);
                    lineList.add(GEOMETRYFACTORY.createLineString(geo.getExteriorRing().getCoordinates()));
                    for (int j = 0; j < geo.getNumInteriorRing(); j++) {
                        lineList.add(GEOMETRYFACTORY.createLineString(geo.getInteriorRingN(i).getCoordinates()));
                    }
                }
                LineString[] lines = new LineString[lineList.size()];
                lineList.toArray(lines);
                res = GEOMETRYFACTORY.createMultiLineString(lines);
            } else {
                //包含一个面，面中包含环
                Polygon poly = (Polygon) geom.getGeometryN(0);
                lineList.add(GEOMETRYFACTORY.createLineString(poly.getExteriorRing().getCoordinates()));
                for (int i = 0; i < poly.getNumInteriorRing(); i++) {
                    lineList.add(GEOMETRYFACTORY.createLineString(poly.getInteriorRingN(i).getCoordinates()));
                }
                LineString[] lines = new LineString[lineList.size()];
                lineList.toArray(lines);
                res = GEOMETRYFACTORY.createMultiLineString(lines);
            }
        } else if ("POLYGON".equals(geometryType)) {
            //只包含一个面
            res = GEOMETRYFACTORY.createLineString(geom.getCoordinates());
        } else {
            res = null;
        }
        return res;
    }

    /**
     * 计算面与线的交点
     *
     * @param geom
     * @param line
     * @return
     */
    public static Geometry getPointOfIntersection(Geometry geom, Geometry line) {
        Geometry lines = polygon2LineString(geom);
        return lines.intersection(line);
    }

    /**
     * wkt转Geometry
     *
     * @param wkt
     * @return
     */
    public static Geometry wkt2Geometry(String wkt) {
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        WKTReader wktReader = new WKTReader(geometryFactory);
        Geometry geometry = null;

        try {
            Geometry read = wktReader.read(wkt);
            return geometry;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 创建一个点
     *
     * @param lon
     * @param lat
     * @return
     */
    public static Point creatrPoint(String lon, String lat) {
        Coordinate coordinate = new Coordinate(Double.parseDouble(lon), Double.parseDouble(lat));
        Point point = GEOMETRYFACTORY.createPoint(coordinate);
        return point;
    }

    /**
     * 使用拼好的字符串来创建一个点
     *
     * @param coor
     * @return
     * @throws ParseException
     */
    public static Point creatrPoint(String coor) throws ParseException {
        Point p = (Point) WKTREADER.read(coor);
        return p;
    }

    /**
     * 创建一个Polygon
     *
     * @param polygon
     * @return
     * @throws ParseException
     */
    public static Polygon createPolygon(String polygon) throws ParseException {
        Polygon p = (Polygon) WKTREADER.read(polygon);
        return p;
    }

    /**
     * 使用拼接好的字符串来创建一个LineString
     *
     * @param line
     * @return
     * @throws ParseException
     */
    public static LineString createLineString(String line) throws ParseException {
        LineString lineString = (LineString) WKTREADER.read(line);
        return lineString;
    }

    /**
     * 比较两个点是否相同,
     *
     * @param p1
     * @param p2
     * @return
     * @throws ParseException
     */
    public static boolean equalsLinePoint(String p1, String p2, int srid) throws ParseException {
        Point geom1 = (Point) WKTREADER.read(p1);
        geom1.setSRID(srid);
        Point geom2 = (Point) WKTREADER.read(p2);
        geom2.setSRID(srid);
        return geom1.equals(geom2);
    }

    /**
     * 比较两个线是否相同
     *
     * @param l1
     * @param l2
     * @return
     * @throws ParseException
     */
    public static boolean equalsLineString(String l1, String l2) throws ParseException {
        LineString geom1 = (LineString) WKTREADER.read(l1);
        LineString geom2 = (LineString) WKTREADER.read(l2);
        return geom1.equals(geom2);
    }


    /**
     * 比较两个面是否相同
     *
     * @param p1
     * @param p2
     * @return
     * @throws ParseException
     */
    public static boolean equalsPolygon(String p1, String p2) throws ParseException {
        Polygon geom1 = (Polygon) WKTREADER.read(p1);
        Polygon geom2 = (Polygon) WKTREADER.read(p2);
        return geom1.equals(geom2);
    }

    /**
     * 线对象有没有交点
     *
     * @param s1
     * @param s2
     * @return
     * @throws ParseException
     */
    public static boolean disjoinLineString(String s1, String s2) throws ParseException {
        LineString line1 = (LineString) WKTREADER.read(s1);
        LineString line2 = (LineString) WKTREADER.read(s2);
        return line1.disjoint(line2);
    }


    /**
     * 面对象有没有交点
     *
     * @param s1
     * @param s2
     * @return
     * @throws ParseException
     */
    public static boolean disjoinPolygon(String s1, String s2) throws ParseException {
        Polygon p1 = (Polygon) WKTREADER.read(s1);
        Polygon p2 = (Polygon) WKTREADER.read(s2);
        return p1.disjoint(p2);
    }

    /**
     * 判断两条线是否相交
     *
     * @param s1
     * @param s2
     * @return
     * @throws ParseException
     */
    public static boolean interSectionOfLineStringAndLineString(String s1, String s2) throws ParseException {
        LineString l1 = (LineString) WKTREADER.read(s1);
        LineString l2 = (LineString) WKTREADER.read(s1);
        Geometry points = l1.intersection(l2);
        return l1.intersects(l2);
    }

    /**
     * 判断两条线是否相交,并返回坐标数组
     * 该方法为初写方法，未经实际检验
     *
     * @param s1
     * @param s2
     * @return
     * @throws ParseException
     */
    public static Coordinate[] interSectionOfLineStringAndLineString(String s1, String s2, int srid) throws ParseException {
        LineString l1 = (LineString) WKTREADER.read(s1);
        LineString l2 = (LineString) WKTREADER.read(s1);
        Geometry points = l1.intersection(l2);
        Coordinate[] coordinates = points.getCoordinates();
        return coordinates;
    }

    /**
     * point[]转Polygon
     *
     * @param s
     * @return
     * @throws ParseException
     */
    public static Polygon pointArray2Polygon(String s) throws ParseException {
        return (Polygon) WKTREADER.read(s);
    }

    /**
     * 返回Polygon区域的点数组
     *
     * @param polygon
     * @param lon
     * @param lat
     * @return
     */
    public static List<Point> IntersectionPointsAndPolygon(Polygon polygon, String lon, String lat) {
        List<Point> points = new ArrayList<>();
        Point point = creatrPoint(lon, lat);
        boolean contains = polygon.contains(point);
        if (contains) {
            points.add(point);
        }
        return points;
    }


    /**
     * 返回Polygon区域的点数组
     *
     * @param polygon
     * @param coor
     * @return
     */
    public static List<Point> IntersectionPointsAndPolygon(Polygon polygon, String coor) throws ParseException {
        List<Point> points = new ArrayList<>();
        Point point = creatrPoint(coor);
        boolean contains = polygon.contains(point);
        if (contains) {
            points.add(point);
        }
        return points;
    }

    /**
     * 计算两个区域的是否相交
     *
     * @param p1
     * @param p2
     * @return
     */
    public static boolean isIntersects(Polygon p1, Polygon p2) {
        boolean flag = p1.intersects(p2);
        return flag;
    }


    /**
     * 计算两个区域是否相交,并返回交叉区域
     *
     * @param p1
     * @param p2
     * @return
     */
    public static Polygon intersectsArea(Polygon p1, Polygon p2) {
        Polygon geom = (Polygon) p1.intersection(p2);
        return geom;
    }

    /**
     * 返回给定位置的缓冲区范围
     *
     * @param point
     * @param range
     * @return
     * @throws ParseException
     */
    public static Polygon fireArea(String point, double range) throws ParseException {
        Point fire = (Point) WKTREADER.read(point);
        Polygon buffer = (Polygon) fire.buffer(range);
        return buffer;
    }

    /**
     * 返回两个点之间的距离
     *
     * @param p1
     * @param p2
     * @return
     */
    public static double distanceOfPoint(Point p1, Point p2) {
        return p1.distance(p2);
    }

    /**
     * 返回两个点之间的距离
     *
     * @param lon1
     * @param lon2
     * @param lat1
     * @param lat2
     * @return
     */
    public static double distanceOfPoint(String lon1, String lon2, String lat1, String lat2) {
        Point p1 = creatrPoint(lon1, lat1);
        Point p2 = creatrPoint(lat2, lon2);
        return p1.distance(p2);
    }

    /**
     * 给定起始点、目标点和移动速度，返回机动至目标点的使用时间
     *
     * @param start
     * @param end
     * @param speed
     * @return
     */
    public static double timeOfGoal(Coordinate start, Coordinate end, float speed) {
        return (start.distance3D(end)) / speed;
    }
}
